package com.ali.ttt.netty.cluster.config;


import cn.hutool.core.collection.CollUtil;
import com.ali.ttt.core.cocurrent.FutureTaskScheduler;
import com.ali.ttt.netty.client.config.NettyClient;
import com.ali.ttt.netty.cluster.domain.ClientList;
import com.ali.ttt.netty.common.domain.Client;
import com.ali.ttt.netty.common.domain.Message;
import com.ali.ttt.netty.common.utils.MessageUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.util.concurrent.GenericFutureListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

@Slf4j
@Component
public class Cluster {

    @Resource
    private NettyClusterProperties nettyClusterProperties;
    @Resource
    private NettyClient nettyClient;
    @Resource
    private RedisTemplate<String, Client> redisTemplate;

    public List<Client> getAll() {
        redisTemplate.setValueSerializer(RedisSerializer.java());
        Long size = redisTemplate.opsForList().size(nettyClusterProperties.getKey());
        return redisTemplate.opsForList().range(nettyClusterProperties.getKey(),0,size-1);
    }
    public void registration() throws UnknownHostException {
        redisTemplate.setValueSerializer(RedisSerializer.java());
        // 查看是否存在其他节点
        List<Client> other = getAll();
        Client own = new Client(InetAddress.getLocalHost().getHostAddress(),nettyClusterProperties.getProd());
        if(CollUtil.isNotEmpty(other)){
            // 通知新节点上线
            for (Client client : other) {
                AtomicReference<Channel> channel = new AtomicReference<>();
                GenericFutureListener<ChannelFuture> closeListener = (ChannelFuture f) ->
                {
                    log.info("连接已经断开……");
                    channel.set(f.channel());
                };
                GenericFutureListener<ChannelFuture> connectedListener= (ChannelFuture f) ->
                {
                    if (f.isSuccess()){
                        log.info("\n----------------------------------------------------------\n\t" +
                                        "netty客户端 连接成功\n\t" +
                                        "External: \t\033[1;34m{}:{}\033[0m\n\t" +
                                        "----------------------------------------------------------",
                                client.getHost(),
                                client.getProd()
                        );
                        channel.set(f.channel());
                        channel.get().closeFuture().addListener(closeListener);
                        // 把自己的信息发送给服务器
                        Message<Client> online = new Message<>();
                        online.setPath("/cluster/login");
                        online.setMsg(own);
                        MessageUtil.send(channel.get(),online);
                    } else {
                        log.info("连接失败! ");
                        // 清除注册信息
                        redisTemplate.setValueSerializer(RedisSerializer.java());
                        redisTemplate.opsForList().remove(nettyClusterProperties.getKey(),1,client);
                    }
                };
                FutureTaskScheduler.add(() ->
                {
                    // 链接其他节点
                    nettyClient.setHost(client.getHost());
                    nettyClient.setPort(client.getProd());
                    nettyClient.setConnectedListener(connectedListener);
                    nettyClient.setCloseListener(closeListener);
                    nettyClient.doConnect();
                    ClientList.inst().addServer(client);
                });
            }
        }
        redisTemplate.opsForList().rightPush(nettyClusterProperties.getKey(),own);
    }

    public void logout() throws UnknownHostException {
        redisTemplate.setValueSerializer(RedisSerializer.java());
        Client client = new Client(InetAddress.getLocalHost().getHostAddress(),nettyClusterProperties.getProd());
        redisTemplate.opsForList().remove(nettyClusterProperties.getKey(),1,client);
    }


}
